﻿#include "mainwindow.h"
#include <QFont>
#include <QPoint>
#include <QString>
#include <QPainter>
#include <QMessageBox>
#include <ctime>
#include <cmath>
#include <iostream>
#include <cstdlib>
#include<math.h>
#include <QElapsedTimer>
//#include<QSound>
#include <QtCore/QCoreApplication>
#include <QtMultimedia/QMediaPlayer>
#include<QIcon>
#include<QBitmap>
#include<QProcess>
//用于移动球的宏
#define Move(ball)\
    QPoint p2=QPoint(ball.x,ball.y);\
    QPixmap pix;\
    switch(ball.type){\
    case 0:{pix.load(":/0.png");break;}\
    case 1:{pix.load(":/1.png");break;}\
    case 2:{pix.load(":/2.png");break;}\
    case 3:{pix.load(":/3.png");break;}\
    case 4:{pix.load(":/4.png");break;}\
    case 5:{pix.load(":/5.png");break;}\
    case 6:{pix.load(":/6.png");break;}\
    case 7:{pix.load(":/7.png");break;}\
    case 8:{pix.load(":/8.png");break;}\
    case 9:{pix.load(":/9.png");break;}\
}\
    paint.drawPixmap(ball.x-ball.size,ball.y-ball.size,2*ball.size,2*ball.size,pix);\

long long int time1;//记录扔球的时间间隔
double K=0.2;
const double speedlimit=10;
double X0,Y0;
const int HEIGHT=870;  //界面高度
const int WIDTH=515;   //界面宽度
const int TOPLINE=80;    //顶部高度
//状态status常量
const int CLEAR=2;
const int START=1;
const int STOP=0;
const int SHOW1=3;
const int BOOM=4;
const int win=5;
int gamescore=0;
QString str;
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setFixedSize(WIDTH,HEIGHT);     //固定窗口大小（不能改变）
    setWindowTitle("NKU合成大西瓜");
    iniUI();            //初始化界面
    iniSignals();       //按钮与函数的信号连接
    status=STOP;        //游戏开始前状态为STOP
    setMouseTracking(true);     //开启鼠标移动事件

    startTimer(25);     //启动计时器并设置帧率为20ms
    nextBall();         //生成第一个球
    //设置背景色
    QPalette pal;
    pal.setColor(QPalette::Background, Qt::white);
    this->setAutoFillBackground(true);
    this->setPalette(pal);
    //计分
    q = new QLabel(this);
    str.sprintf("score:%d",gamescore);
    q->setText(str);
    q->setStyleSheet("color: white");
    q->resize(WIDTH,TOPLINE);
    QFont ft1;
    QFont::Bold - 75 ;
    ft1.setPointSize(40);
    q->move(0,5);
    q->setFont(ft1);
    q->hide();


}
MainWindow::~MainWindow()
{
    delete Start;
    delete Rank;
    delete Exit;
    delete Back;
    delete Pause;
    delete Finish;
    delete q;
    delete Win;

}
void MainWindow::setbutton(QPushButton *B,int width,int height, int x, int y, QString str)
{
    const int FSIZE=WIDTH/21;   //按钮的字体大小
    QFont font;
    font.setPointSize(FSIZE);
    font.setWeight(3);          //字体粗细
    B->resize(width,height);    //按钮大小
    B->setText(str);            //设置按钮文字
    B->move(x,y);               //将按钮放在(x,y)处
    B->setFont(font);

}
void MainWindow::Setbutton(QPushButton *B, int width, int height, int x, int y, int a)
{

    B->move(x,y);               //将按钮放在(x,y)处
    if(a==1){
        QPixmap pixmap(":/stephe/nankai.jpg");
        pixmap = pixmap.scaled (100, 100, Qt::IgnoreAspectRatio);
        B->setMask(QBitmap(pixmap.mask()));
        QIcon button_ico(":/stephe/nankai.jpg");
        B->setIcon(button_ico);
        B->setFixedSize(pixmap.size());
        B->setIconSize(QSize(100,100));
    }
    else if(a==2){
        QPixmap pixmap1(":/stephe/nankai.jpg");
        pixmap1 = pixmap1.scaled (100, 100, Qt::IgnoreAspectRatio);
        B->setMask(QBitmap(pixmap1.mask()));
        QIcon button_ico(":/8.png");
        B->setIcon(button_ico);
        B->setFixedSize(pixmap1.size());
        B->setIconSize(QSize(175,175));
    }
    else if(a==3){
        QPixmap pixmap2(":/8.png");
        pixmap2 = pixmap2.scaled (100, 100, Qt::IgnoreAspectRatio);
        B->setMask(QBitmap(pixmap2.mask()));
        QIcon button_ico(":/9.png");
        B->setIcon(button_ico);
        B->setFixedSize(pixmap2.size());
        B->setIconSize(QSize(152,152));

    }
    else if(a==4){
        QPixmap pixmap2(":/8.png");
        pixmap2 = pixmap2.scaled (100, 100, Qt::IgnoreAspectRatio);
        B->setMask(QBitmap(pixmap2.mask()));
        QIcon button_ico(":/9.png");
        B->setIcon(button_ico);
        B->setFixedSize(pixmap2.size());
        B->setIconSize(QSize(150,150));

    }
    else if(a==5){
        QPixmap pixmap2(":/8.png");
        pixmap2 = pixmap2.scaled (150, 150, Qt::IgnoreAspectRatio);
        B->setMask(QBitmap(pixmap2.mask()));
        QIcon button_ico(":/9.png");
        B->setIcon(button_ico);
        B->setFixedSize(pixmap2.size());
        B->setIconSize(QSize(180,180));

    }
    if(a==6){
        B->resize(width,height);
        QPixmap pixmap(":/8.png");
        pixmap = pixmap.scaled (100, 100, Qt::IgnoreAspectRatio);
        B->setMask(QBitmap(pixmap.mask()));
        QIcon button_ico(":/9.png");
        B->setIcon(button_ico);
        B->setFixedSize(pixmap.size());
        B->setIconSize(QSize(100,100));
    }


}
void MainWindow::onRestart() {//重启
    qApp->quit();
    QProcess::startDetached(qApp->applicationFilePath(), QStringList());
}
void MainWindow::iniUI()
{


    //按钮的宽和高
    const int BWIDTH=WIDTH/3;
    const int BHEIGHT=HEIGHT/9;
    //按钮初始化
    Start=new QPushButton(this);
    Win=new QPushButton(this);
    Rank=new QPushButton(this);
    Exit=new QPushButton(this);
    Back=new QPushButton(this);
    Pause=new QPushButton(this);
    Finish=new QPushButton(this);

    Setbutton(Start,BWIDTH,BHEIGHT,146,BHEIGHT*4.59,1);
    Setbutton(Rank,BWIDTH,BHEIGHT,232,BHEIGHT*5.15,2);
    Setbutton(Exit,BWIDTH,BHEIGHT,324,BHEIGHT*5.65,3);
    Setbutton(Back,BWIDTH,BHEIGHT,BWIDTH*1.2,BHEIGHT*7,4);
    setbutton(Pause,40,40,WIDTH-45,5,"||");
    Setbutton(Finish,BWIDTH,BHEIGHT*2,220,BHEIGHT*4,5);
    Setbutton(Win,500,250,220,BHEIGHT*4,6);
    //隐藏"返回"和"暂停"按钮
    Back->hide();
    Pause->hide();
    Finish->hide();
    Win->hide();
}
void MainWindow::showbuttons(bool aa)//控制界面三个按钮的显示
{
    if (aa==true)
    {
        Start->show();
        Rank->show();
        Exit->show();
    }
    else
    {
        Start->hide();
        Rank->hide();
        Exit->hide();
    }
}
void MainWindow::StartGame()
{

    //status=win;
    q->show();
    status=START;      //设置游戏状态为START
    showbuttons(false); //隐藏初始界面的按钮
    Pause->show();      //显示暂停按钮
    Pause->raise();      //上层显示
   // Win->show();
}
void MainWindow::showscore()//查看
{
    status=SHOW1;
    showbuttons(false);
    Back->show();

}
void MainWindow::back()
{
    status=SHOW1;
    showbuttons(true);
    Back->hide();
    //Pause->show();
    onRestart();
}
void MainWindow::gamepause()
{
    //status=STOP;
    int ret = QMessageBox::information(0,"info",QStringLiteral("游戏暂停"),QStringLiteral("继续游戏"),QStringLiteral("返回菜单"),"",1);
    if (ret==0)     //  继续游戏
    {
        status=START;
    }
    else if (ret==1)    //  返回菜单
    {
        status=CLEAR;   //清屏
        update();
        showbuttons(true);
        Pause->hide();
        status=STOP;    //停止游戏
        onRestart();
    }

}
void MainWindow::gamefinish()
{


        Finish->hide();
        status=CLEAR;   //清屏
        update();
        showbuttons(true);//  返回菜单

        status=STOP;    //停止游戏


}
void MainWindow::gamewin()
{
    status=win;
    onRestart();
}
void MainWindow::iniSignals()
{
    //退出按钮
    connect(Exit,SIGNAL(clicked()),this,SLOT(close()));
    //开始按钮
    connect(Start,SIGNAL(clicked()),this,SLOT(StartGame()));
    //积分按钮
    connect(Rank,SIGNAL(clicked()),this,SLOT(showscore()));
    //返回按钮
    connect(Back,SIGNAL(clicked()),this,SLOT(back()));
    //暂停按钮
    connect(Pause,SIGNAL(clicked()),this,SLOT(gamepause()));
    //结束按钮
    connect(Finish,SIGNAL(clicked()),this,SLOT(gamefinish()));
    //计时
    //connect(timer2,SIGNAL(timeout()),this,SLOT()
    //胜利按钮
    connect(Win,SIGNAL(clicked()),this,SLOT(gamewin()));
}
void MainWindow::nextBall()
{
    //随机生成下一个球的种类
    srand((unsigned)time(NULL));
    unfallingBall.type=rand()%5;
    //根据种类设置大小、质量和颜色
    unfallingBall.initball(unfallingBall.type);
    int x1;
    //判断生成的球是否出界，并设置其坐标
    if (mouse.x()<unfallingBall.size) x1=unfallingBall.size;
    else if (mouse.x()>WIDTH-unfallingBall.size) x1=WIDTH-unfallingBall.size;
    else x1=mouse.x();
    unfallingBall.x=unfallingBall._x=x1;
    unfallingBall.y=unfallingBall._y=5+unfallingBall.size;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
    if(status==STOP )
    {
    QPainter p(this);
    p.drawPixmap(0,0,WIDTH,HEIGHT,QPixmap(":/stephe/nankai.jpg"));
    }
    if (status==START)
    {
        QPainter paint(this);
        paint.drawPixmap(0,0,QPixmap(":/stephe/nankai.jpg"));
        //清屏
        paint.drawPixmap(-1,TOPLINE+25,QPixmap(":/Line.png"));
        paint.setRenderHint(QPainter::Antialiasing);
        Move(unfallingBall)//调用Move宏移动未下落的球
        for (int i=0;i<balls.size();i++)
        {
            Move(balls[i])
        }
    }

    else if (status==CLEAR) //清屏
    {
        QPainter paint(this);

        paint.setBrush(QBrush(Qt::white,Qt::SolidPattern));
        paint.drawRect(QRect(0,0,WIDTH,HEIGHT));
        paint.drawPixmap(0,0,QPixmap(":/stephe/nankai.jpg"));
    }
    else if (status==SHOW1) //清屏
    {
        QPainter paint(this);


        paint.drawPixmap(0,0,QPixmap(":/stephe/nankai.jpg"));
    }
    else if (status==BOOM) //清屏
    {
        QPainter paint(this);
        paint.drawPixmap(int(X0),int(Y0),QPixmap(":/stephe/nankai.jpg"));
    }
    else if (status==win) //清屏
    {
        QPainter paint(this);
        QPixmap pix(":/3.png");
        pix.scaled(500,250);
        paint.drawPixmap(0,0,pix);
    }

}
void MainWindow::mouseMoveEvent(QMouseEvent *event) //鼠标移动时球跟着鼠标走
{
    if (status==START)
    {
        mouse=event->pos();
        if (mouse.x()<unfallingBall.size||mouse.x()>WIDTH-unfallingBall.size) return;//鼠标出界则不移动球
        //鼠标出界则将边界作为球的坐标
        int x1;
        if (mouse.x()<unfallingBall.size) x1=unfallingBall.size;
        else if (mouse.x()>WIDTH-unfallingBall.size) x1=WIDTH-unfallingBall.size;
        else x1=mouse.x();
        //更新未下落球的坐标和鼠标的坐标
        unfallingBall.x=x1;
        mouse=event->pos();
        update();      //触发paintEvent事件
    }
}
void MainWindow::mousePressEvent(QMouseEvent *event)    //单机鼠标左键则使球下落
{
    if (status==START)
    {
        if(event->button() == Qt::LeftButton&&time1==0)
        {
            unfallingBall.vy=5; //下落速度
            unfallingBall.ay=1;  //重力场加速度
            balls.push_back(unfallingBall);      //将下落的球存入数组balls
            time1=clock();      //鼠标按下后一段时间后再生成新球
            unfallingBall.y=-100;
        }
    }
}
void MainWindow::timerEvent(QTimerEvent *event)
{
    if (status==STOP) return;
    if (clock()-time1>CLOCKS_PER_SEC&&time1!=0)
    {
        time1=0;
        nextBall();
    }
    movecoordinate();
    update();
}
void MainWindow::movecoordinate()       //根据每个球速度移动球的坐标
{
    for (int i=0;i<balls.size();i++)
    {
        balls[i].vx+=balls[i].ax;
        balls[i].vy+=balls[i].ay;
        balls[i]._x=balls[i].x;
        balls[i]._y=balls[i].y;
        balls[i].x+=balls[i].vx;
        balls[i].y+=balls[i].vy;
        collideWall(i);
    }
    collision();    //碰撞
    for (int i=0;i<balls.size();i++)collideWall(i);
    for (int i=0;i<balls.size();i++)
    {
        if(balls[i].type==9){
            QPainter paint(this);
            paint.drawPixmap(0,0,QPixmap(":/res/win.png"));
            //status=STOP;
        }
    }
}
void MainWindow::collideWall(int i)//判断撞墙
{
    if (balls[i].x>=WIDTH-balls[i].size)
    {
        balls[i].x=WIDTH-balls[i].size;//防止速度过快穿过墙
        balls[i].vx=-balls[i].vx*K*0.5;
    }   //撞右边的墙
    if (balls[i].x<=balls[i].size)
    {
        balls[i].x=balls[i].size;//防止速度过快穿过墙
        balls[i].vx=-balls[i].vx*K*0.5;
    }   //撞左边的墙
    if (balls[i].y>=HEIGHT-balls[i].size)
    {
        balls[i].y=HEIGHT-balls[i].size;//防止速度过快穿过下墙
        balls[i].vy=-balls[i].vy*K*0.5;
    }
    if (balls[i].falling==1)    //若falling=0，则球还在边界上方未落下
    {
        if (balls[i].y-balls[i].size<=TOPLINE)//判断越界
        {
            for (int j=0;j<balls.size();j++)
            {
                gamescore+=balls[j].type*2;
            }
            //sleep(5);
            status=STOP;
            Finish->show();
        }
    }
    else if (balls[i].y>TOPLINE+balls[i].size) balls[i].falling=1;

    if (balls[i].y==HEIGHT-balls[i].size)//设置摩擦
    {
        if(balls[i].vx<balls[i].ax)
        balls[i].vx=0;

        if(balls[i].vx!=0){
            if (balls[i].vx<0) balls[i].ax=0.1; //向右摩擦力   //撞墙
            if (balls[i].vx>0) balls[i].ax=-0.1;  //向左摩擦力

        }


    }

    else if (balls[i].y<HEIGHT-balls[i].size)// x加速度置零
    {
        balls[i].ax=0;
    }

}
void MainWindow::collision()
{
    for (int i=0;i<balls.size();i++)
    {
        for (int j=0;j<balls.size();j++)
        {
            if (i==j) continue;
            //判断两球是否相邻
            double dx=balls[i].x-balls[j].x;
            double dy=balls[i].y-balls[j].y;
            double distance=sqrt(dx*dx+dy*dy);
            double D=balls[i].size+balls[j].size;
            if (distance>D) continue;
            //两球种类相同则合成
            if (balls[i].type==balls[j].type)
            {
                combine(i,j);
                X0=balls[i].x;
                Y0=balls[i].y;
                status=BOOM;

                update();
                status=START;
                //sound->play();//播放
                continue;
            }
            double vi=sqrt(balls[i].vx*balls[i].vx+balls[i].vy*balls[i].vy);
            double vj=sqrt(balls[j].vx*balls[j].vx+balls[j].vy*balls[j].vy);
            if (vi>speedlimit||vj>speedlimit)//若速度过快，强制沿原方向退回一段距离
            {
                double dxi=(balls[i]._x-balls[i].x)/10.0;
                double dyi=(balls[i]._y-balls[i].y)/10.0;
                double dxj=(balls[j]._x-balls[j].x)/10.0;
                double dyj=(balls[j]._y-balls[j].y)/10.0;
                for (int k=0;k<10&&distance-D<0;k++)
                {
                    balls[i].x+=dxi;
                    balls[i].y+=dyi;
                    balls[j].x+=dxj;
                    balls[j].y+=dyj;
                    dx=balls[i].x-balls[j].x;
                    dy=balls[i].y-balls[j].y;
                    distance=sqrt(dx*dx+dy*dy+0.0);
                }
            }
            double ex=dx/distance,ey=dy/distance;//法向单位向量(ex,ey)，方向由j指向i
            if (distance<D) //对重叠在一起的球进行位置修正
            {
                double dd=D-distance;
                balls[j].x-=dd*ex*balls[i].mass/(balls[i].mass+balls[j].mass);
                balls[i].x+=dd*ex*balls[j].mass/(balls[i].mass+balls[j].mass);
                if (balls[i].y>balls[j].y) balls[j].y-=fabs(dd*ey);
                else balls[i].y-=fabs(dd*ey);}

            double ux=-dy/distance,uy=dx/distance;//切向单位向量(ux,uy),方向为(ex,ey)逆时针旋转π/2
            //球在两球连线方向上的速度投影为v=(vx,vy)·(ex,ey)
            double v1=ex*balls[i].vx+ey*balls[i].vy;//i的法向速度
            double v2=ex*balls[j].vx+ey*balls[j].vy;//j的法向速度
            if (v2<v1) continue;//两球擦肩而过，不相撞
            //球在切线方向上的速度投影为v'=(vx,vy)·(ux,uy)
            double v11=ux*balls[i].vx+uy*balls[i].vy;//i的切向速度
            double v22=ux*balls[j].vx+uy*balls[j].vy;//j的切向速度
            //根据动量守恒和动能定理计算碰撞后两球连线方向上的速度u1和u2,其中K表示动能损失程度
            double m1=balls[i].mass,m2=balls[j].mass;
            double u1=K*((m1-m2)*v1+2*m2*v2)/(m1+m2);//i碰撞后法向速度
            double u2=K*((m2-m1)*v2+2*m1*v1)/(m1+m2);//j碰撞后法向速度
            //最终的速度矢量(vx,vy)=(u1*ex+v11*ux,u1*ey+v11*uy)·(i,j)
            balls[i].vx=1*(u1*ex+v11*ux);
            balls[i].vy=1*(u1*ey+v11*uy);
            balls[j].vx=1*(u2*ex+v22*ux);
            balls[j].vy=1*(u2*ey+v22*uy);
        }
    }
}
void MainWindow::combine(int i, int j)
{


    Ball b;
    b.initball(balls[i].type+1);
    double vi=sqrt(balls[i].vx*balls[i].vx+balls[i].vy*balls[i].vy);
    double vj=sqrt(balls[j].vx*balls[j].vx+balls[j].vy*balls[j].vy);
    if (vi<vj)//合成的位置为速度较小的球
    {
        b.x=b._x=balls[i].x;
        b.y=b._y=balls[i].y;
    }
    else {
        b.x=b._x=balls[j].x;
        b.y=b._y=balls[j].y;
    }

    b.vx=(balls[i].vx+balls[j].vx)/2.0;
    b.vy=(balls[i].vy+balls[j].vy)/2.0;
    b.ay=1;
    b.falling=1;

    balls[i]=b;     //将合成的新球替换balls[i]
    collideWall(i);
    balls[j]=balls[balls.size()-1];
    balls.pop_back();   //从balls数组中删除balls[j]
    gamescore+=2*balls[i].type;
    str.sprintf("score:%d",gamescore);
    q->setText(str);

}
